package com.dycong.common.dataStructuresAndAlgorithms;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.text.CollationKey;
import java.text.Collator;
import java.util.*;

/**
 * Created by Duke on 2016/11/9.
 */
public class Chapter1 {

    private static final int COPY_THRESHOLD = 10;
    private static int DEFAULT_CAPACITY = 10;
    Double[] array = new Random().doubles(0, 350000).limit(350000).boxed().toArray(Double[]::new);
    static String[] arrayCher=new String[10000];//// TODO: 2016/11/9 设定静态变量才能在静态代码块里初始化

    static {
        for(int i=0;i<arrayCher.length;i++){
            arrayCher[i]=getRandomString(5);
        }
    }

    /**
     * 递归
     */

    public void print() {
        printOut(8);
    }

    public static void printOut(int n) {
        if (n >= 2) printOut(n >> 1);
        System.out.println(n % 2);
    }

    /**
     * todo 请记住PECS原则：生产者（Producer）使用extends，消费者（Consumer）使用super。

     生产者使用extends
     如果你需要一个列表提供T类型的元素（即你想从列表中读取T类型的元素），你需要把这个列表声明成<? extends T>，比如List<? extends Integer>，因此你不能往该列表中添加任何元素。

     消费者使用super
     如果需要一个列表使用T类型的元素（即你想把T类型的元素加入到列表中），你需要把这个列表声明成<? super T>，比如List<? super Integer>，因此你不能保证从中读取到的元素的类型。

     即是生产者，也是消费者
     如果一个列表即要生产，又要消费，你不能使用泛型通配符声明列表，比如List<Integer>。
     * @param arr
     * @param <T>
     * @return
     */
    public static <T extends Comparable<? super T>> T findMax(T[] arr) {
        int maxIndex = 0;

        for (int i = 1; i < arr.length; i++)
            if (arr[i].compareTo(arr[maxIndex]) > 0)
                maxIndex = i;
        return arr[maxIndex];
    }

    /**
     * todo interface RandomAccess
     * java.util.Collections里的copy方法 RandomAccess
     List 实现所使用的标记接口，用来表明其支持快速（通常是固定时间）随机访问。此接口的主要目的是允许一般的算法更改其行为，从而在将其应用到随机或连续访问列表时能提供良好的性能。

     强调:
     @see  JDK中推荐的是对List集合尽量要实现RandomAccess接口
     如果集合类是RandomAccess的实现，则尽量用for(int i = 0; i < size; i++) 来遍历而不要用Iterator迭代器来遍历，在效率上要差一些。反过来，如果List是Sequence List，则最好用迭代器来进行迭代。

     JDK中说的很清楚，在对List特别是Huge size的List的遍历算法中，要尽量来判断是属于RandomAccess(如ArrayList)还是Sequence List (如LinkedList），因为适合RandomAccess List的遍历算法，用在Sequence List上就差别很大，常用的作法就是：
     要作一个判断：
     if (list instance of RandomAccess) {
     for(int m = 0; m < list.size(); m++){}
     }else{
     Iterator iter = list.iterator();
     while(iter.hasNext()){}
     }
     * @param dest
     * @param src
     * @param <T>
     */
    public static <T> void copy(List<? super T> dest, List<? extends T> src) {
        int srcSize = src.size();
        if (srcSize > dest.size())
            throw new IndexOutOfBoundsException("Source does not fit in dest");

        if (srcSize < COPY_THRESHOLD ||
                (src instanceof RandomAccess && dest instanceof RandomAccess)) {
            for (int i = 0; i < srcSize; i++)
                dest.set(i, src.get(i));
        } else {
            ListIterator<? super T> di = dest.listIterator();
            ListIterator<? extends T> si = src.listIterator();

            /**
             * 泛型数组的调用
             * @see T[] j= (T[])new Object[DEFAULT_CAPACITY];

             */
            for (int i = 0; i < srcSize; i++) {
                di.next();
                di.set(si.next());
            }
        }
    }

    @Data
    @AllArgsConstructor
    public static class Pair {
        private double first;
        private double second;

        public Pair(){

        }
    }


    /**
     * 泛型数组传递及创建
     * @param arr
     * @param <T>
     * @return
     */

    public static <T extends Comparable<? super T>> T[] T_Array(T[] arr) {
        T[] ts=(T[])new Object[DEFAULT_CAPACITY];
        return ts;
    }

    /**
     * 在内部类不需要访问外围类对象的时候，可以使用静态内部类，以便取消产生的引用（静态内部类不持有对外部类的引用）。
     * 生命在接口里的内部类自动成为public、static;
     * 静态内部类可以持有外部类的静态域，静态变量等。
     * @param doubles
     * @return
     */
    public static Pair maxMIn(double[] doubles) {
        double min = Double.MIN_VALUE;
        double max = Double.MAX_VALUE;
        for (double d :doubles){
            if (min>d)min=d;
            if (max<d)max=d;
        }
        DEFAULT_CAPACITY=DEFAULT_CAPACITY;
        return new Pair(min,max);//@see最后min为最大值，max为最小值
    }




    /**
     *自定义比较器的findMax()
     */
    public void testNext() {
        System.out.println(findMax(arrayCher, new Collator() {
            @Override
            public int compare(String source, String target) {
                return source.compareToIgnoreCase(target);
            }

            @Override
            public CollationKey getCollationKey(String source) {
                return null;
            }

            @Override
            public int hashCode() {
                return 0;
            }
        }));
    }

    public static <T> T findMax(T[] array, Comparator<? super T> comparator) {
        int maxIndex = 0;

        for (int i = 1; i < array.length; i++)
            if (comparator.compare(array[i], array[maxIndex]) > 0)
                maxIndex = i;
        return array[maxIndex];

    }


    /**
     * 产生随机指定长度的字符串
     * @param length
     * @return
     */
    public static String getRandomString(int length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }


}
